package com.carbeauty.entity;

import com.carbeauty.common.entity.BaseEntity;
import com.fasterxml.jackson.annotation.JsonFormat;
import jakarta.persistence.*;
import jakarta.validation.constraints.DecimalMin;
import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.NotNull;
import jakarta.validation.constraints.Size;

import java.math.BigDecimal;
import java.time.LocalDateTime;

/**
 * 库存记录实体类
 * 
 * 库存管理功能:
 * - 材料入库记录
 * - 材料出库记录
 * - 库存变动跟踪
 * - 库存盘点记录
 * 
 * 操作类型包括:
 * - 采购入库
 * - 退货出库
 * - 消耗出库
 * - 盘点调整
 * - 报损出库
 * - 调拨入库
 * - 调拨出库
 * 
 * @author CarBeauty Team
 */
@Entity
@Table(name = "cb_stock_record")
public class StockRecord extends BaseEntity {
    
    /**
     * 材料ID - 不使用外键约束
     */
    @NotNull(message = "材料ID不能为空")
    @Column(name = "material_id", nullable = false)
    private Long materialId;
    
    /**
     * 材料名称 - 冗余字段，便于查询
     */
    @Size(max = 100, message = "材料名称长度不能超过100个字符")
    @Column(name = "material_name", length = 100)
    private String materialName;
    
    /**
     * 材料编码 - 冗余字段
     */
    @Size(max = 50, message = "材料编码长度不能超过50个字符")
    @Column(name = "material_code", length = 50)
    private String materialCode;
    
    /**
     * 操作类型
     */
    @NotBlank(message = "操作类型不能为空")
    @Size(max = 20, message = "操作类型长度不能超过20个字符")
    @Column(name = "operation_type", nullable = false, length = 20)
    private String operationType;
    
    /**
     * 操作数量
     */
    @NotNull(message = "操作数量不能为空")
    @DecimalMin(value = "0.01", message = "操作数量必须大于0")
    @Column(name = "quantity", nullable = false, precision = 10, scale = 2)
    private BigDecimal quantity;
    
    /**
     * 单价
     */
    @DecimalMin(value = "0", message = "单价不能为负数")
    @Column(name = "unit_price", precision = 10, scale = 2)
    private BigDecimal unitPrice = BigDecimal.ZERO;
    
    /**
     * 总金额
     */
    @DecimalMin(value = "0", message = "总金额不能为负数")
    @Column(name = "total_amount", precision = 10, scale = 2)
    private BigDecimal totalAmount = BigDecimal.ZERO;
    
    /**
     * 操作前库存
     */
    @DecimalMin(value = "0", message = "操作前库存不能为负数")
    @Column(name = "stock_before", precision = 10, scale = 2)
    private BigDecimal stockBefore = BigDecimal.ZERO;
    
    /**
     * 操作后库存
     */
    @DecimalMin(value = "0", message = "操作后库存不能为负数")
    @Column(name = "stock_after", precision = 10, scale = 2)
    private BigDecimal stockAfter = BigDecimal.ZERO;
    
    /**
     * 操作时间
     */
    @NotNull(message = "操作时间不能为空")
    @Column(name = "operation_date", nullable = false)
    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
    private LocalDateTime operationDate;
    
    /**
     * 操作员ID - 不使用外键约束
     */
    @Column(name = "operator_id")
    private Long operatorId;
    
    /**
     * 操作员姓名 - 冗余字段
     */
    @Size(max = 50, message = "操作员姓名长度不能超过50个字符")
    @Column(name = "operator_name", length = 50)
    private String operatorName;
    
    /**
     * 供应商名称 - 用于入库记录
     */
    @Size(max = 100, message = "供应商名称长度不能超过100个字符")
    @Column(name = "supplier", length = 100)
    private String supplier;
    
    /**
     * 关联订单ID - 用于出库记录
     */
    @Column(name = "order_id")
    private Long orderId;
    
    /**
     * 关联订单号 - 冗余字段
     */
    @Size(max = 32, message = "订单号长度不能超过32个字符")
    @Column(name = "order_no", length = 32)
    private String orderNo;
    
    /**
     * 批次号
     */
    @Size(max = 50, message = "批次号长度不能超过50个字符")
    @Column(name = "batch_no", length = 50)
    private String batchNo;
    
    /**
     * 存放位置
     */
    @Size(max = 100, message = "存放位置长度不能超过100个字符")
    @Column(name = "storage_location", length = 100)
    private String storageLocation;
    
    /**
     * 操作原因
     */
    @Size(max = 200, message = "操作原因长度不能超过200个字符")
    @Column(name = "reason", length = 200)
    private String reason;
    
    /**
     * 操作备注
     */
    @Size(max = 500, message = "操作备注长度不能超过500个字符")
    @Column(name = "operation_remark", length = 500)
    private String operationRemark;
    
    // ==================== 构造方法 ====================
    
    public StockRecord() {
        super();
        this.operationDate = LocalDateTime.now();
    }
    
    public StockRecord(Long materialId, String operationType, BigDecimal quantity) {
        this();
        this.materialId = materialId;
        this.operationType = operationType;
        this.quantity = quantity;
    }
    
    // ==================== Getter/Setter ====================
    
    public Long getMaterialId() {
        return materialId;
    }
    
    public void setMaterialId(Long materialId) {
        this.materialId = materialId;
    }
    
    public String getMaterialName() {
        return materialName;
    }
    
    public void setMaterialName(String materialName) {
        this.materialName = materialName;
    }
    
    public String getMaterialCode() {
        return materialCode;
    }
    
    public void setMaterialCode(String materialCode) {
        this.materialCode = materialCode;
    }
    
    public String getOperationType() {
        return operationType;
    }
    
    public void setOperationType(String operationType) {
        this.operationType = operationType;
    }
    
    public BigDecimal getQuantity() {
        return quantity;
    }
    
    public void setQuantity(BigDecimal quantity) {
        this.quantity = quantity;
        this.calculateTotalAmount();
    }
    
    public BigDecimal getUnitPrice() {
        return unitPrice;
    }
    
    public void setUnitPrice(BigDecimal unitPrice) {
        this.unitPrice = unitPrice;
        this.calculateTotalAmount();
    }
    
    public BigDecimal getTotalAmount() {
        return totalAmount;
    }
    
    public void setTotalAmount(BigDecimal totalAmount) {
        this.totalAmount = totalAmount;
    }
    
    public BigDecimal getStockBefore() {
        return stockBefore;
    }
    
    public void setStockBefore(BigDecimal stockBefore) {
        this.stockBefore = stockBefore;
    }
    
    public BigDecimal getStockAfter() {
        return stockAfter;
    }
    
    public void setStockAfter(BigDecimal stockAfter) {
        this.stockAfter = stockAfter;
    }
    
    public LocalDateTime getOperationDate() {
        return operationDate;
    }
    
    public void setOperationDate(LocalDateTime operationDate) {
        this.operationDate = operationDate;
    }
    
    public Long getOperatorId() {
        return operatorId;
    }
    
    public void setOperatorId(Long operatorId) {
        this.operatorId = operatorId;
    }
    
    public String getOperatorName() {
        return operatorName;
    }
    
    public void setOperatorName(String operatorName) {
        this.operatorName = operatorName;
    }
    
    public String getSupplier() {
        return supplier;
    }
    
    public void setSupplier(String supplier) {
        this.supplier = supplier;
    }
    
    public Long getOrderId() {
        return orderId;
    }
    
    public void setOrderId(Long orderId) {
        this.orderId = orderId;
    }
    
    public String getOrderNo() {
        return orderNo;
    }
    
    public void setOrderNo(String orderNo) {
        this.orderNo = orderNo;
    }
    
    public String getBatchNo() {
        return batchNo;
    }
    
    public void setBatchNo(String batchNo) {
        this.batchNo = batchNo;
    }
    
    public String getStorageLocation() {
        return storageLocation;
    }
    
    public void setStorageLocation(String storageLocation) {
        this.storageLocation = storageLocation;
    }
    
    public String getReason() {
        return reason;
    }
    
    public void setReason(String reason) {
        this.reason = reason;
    }
    
    public String getOperationRemark() {
        return operationRemark;
    }
    
    public void setOperationRemark(String operationRemark) {
        this.operationRemark = operationRemark;
    }
    
    // ==================== 业务方法 ====================
    
    /**
     * 计算总金额
     */
    public void calculateTotalAmount() {
        if (quantity != null && unitPrice != null) {
            this.totalAmount = quantity.multiply(unitPrice);
        }
    }
    
    /**
     * 计算库存变化
     */
    public void calculateStockChange(BigDecimal beforeStock) {
        this.stockBefore = beforeStock;
        
        if (isInboundOperation()) {
            this.stockAfter = beforeStock.add(quantity);
        } else if (isOutboundOperation()) {
            this.stockAfter = beforeStock.subtract(quantity);
        } else {
            this.stockAfter = beforeStock;
        }
    }
    
    /**
     * 检查是否为入库操作
     */
    public boolean isInboundOperation() {
        return TYPE_PURCHASE_IN.equals(operationType) || 
               TYPE_RETURN_IN.equals(operationType) ||
               TYPE_TRANSFER_IN.equals(operationType) ||
               TYPE_ADJUST_IN.equals(operationType);
    }
    
    /**
     * 检查是否为出库操作
     */
    public boolean isOutboundOperation() {
        return TYPE_CONSUME_OUT.equals(operationType) ||
               TYPE_RETURN_OUT.equals(operationType) ||
               TYPE_TRANSFER_OUT.equals(operationType) ||
               TYPE_DAMAGE_OUT.equals(operationType) ||
               TYPE_ADJUST_OUT.equals(operationType);
    }
    
    /**
     * 生成批次号
     */
    public void generateBatchNo() {
        if (this.batchNo == null || this.batchNo.isEmpty()) {
            // 格式: 操作类型首字母 + 年月日 + 4位随机数
            String typeCode = operationType.substring(0, 1).toUpperCase();
            String date = LocalDateTime.now().format(java.time.format.DateTimeFormatter.ofPattern("yyyyMMdd"));
            String random = String.format("%04d", (int)(Math.random() * 10000));
            this.batchNo = typeCode + date + random;
        }
    }
    
    // ==================== 操作类型常量 ====================
    
    /**
     * 采购入库
     */
    public static final String TYPE_PURCHASE_IN = "采购入库";
    
    /**
     * 退货入库
     */
    public static final String TYPE_RETURN_IN = "退货入库";
    
    /**
     * 消耗出库
     */
    public static final String TYPE_CONSUME_OUT = "消耗出库";
    
    /**
     * 退货出库
     */
    public static final String TYPE_RETURN_OUT = "退货出库";
    
    /**
     * 报损出库
     */
    public static final String TYPE_DAMAGE_OUT = "报损出库";
    
    /**
     * 调拨入库
     */
    public static final String TYPE_TRANSFER_IN = "调拨入库";
    
    /**
     * 调拨出库
     */
    public static final String TYPE_TRANSFER_OUT = "调拨出库";
    
    /**
     * 盘点调增
     */
    public static final String TYPE_ADJUST_IN = "盘点调增";
    
    /**
     * 盘点调减
     */
    public static final String TYPE_ADJUST_OUT = "盘点调减";
}
